<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-cn">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Redis系列之（二）：Redis主从同步，读写分离 - ee900222 - 博客园</title>
<link type="text/css" rel="stylesheet" href="/bundles/blog-common.css?v=Jsknfrse2BShd-7DrxM42RyulObn44e4JjkI6-WX6zk1"/>
<link id="MainCss" type="text/css" rel="stylesheet" href="/skins/iMetro_HD/bundle-iMetro_HD.css?v=9G-AuFYmpxqkeOPQcw_WAuPfB2xUfxYK7gabXn6lD881"/>
<link title="RSS" type="application/rss+xml" rel="alternate" href="http://www.cnblogs.com/ee900222/rss"/>
<link title="RSD" type="application/rsd+xml" rel="EditURI" href="http://www.cnblogs.com/ee900222/rsd.xml"/>
<link type="application/wlwmanifest+xml" rel="wlwmanifest" href="http://www.cnblogs.com/ee900222/wlwmanifest.xml"/>
<script src="http://common.cnblogs.com/script/jquery.js" type="text/javascript"></script>  
<script type="text/javascript">var currentBlogApp = 'ee900222', cb_enable_mathjax=false;</script>
<script src="/bundles/blog-common.js?v=V3tkfsuahqfUzgmqZVwj2QjsxodIvgDfvPKdn8yDuMY1" type="text/javascript"></script>
</head>
<body>
<a name="top"></a>

<!--done-->
<div id="home">
<div id="header">
	<div id="blogTitle">
	<a id="lnkBlogLogo" href="http://www.cnblogs.com/ee900222/"><img id="blogLogo" src="/Skins/custom/images/logo.gif" alt="返回主页" /></a>			
		
<!--done-->
<h1><a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/ee900222/">ee900222</a></h1>
<h2></h2>



		
	</div><!--end: blogTitle 博客的标题和副标题 -->
	<div id="navigator">
		
<ul id="navList">
<li><a id="MyLinks1_HomeLink" class="menu" href="http://www.cnblogs.com/">博客园</a></li>
<li><a id="MyLinks1_MyHomeLink" class="menu" href="http://www.cnblogs.com/ee900222/">首页</a></li>
<li><a id="MyLinks1_NewPostLink" class="menu" rel="nofollow" href="http://i.cnblogs.com/EditPosts.aspx?opt=1">新随笔</a></li>
<li><a id="MyLinks1_ContactLink" class="menu" rel="nofollow" href="http://msg.cnblogs.com/send/ee900222">联系</a></li>
<li><a id="MyLinks1_Syndication" class="menu" href="http://www.cnblogs.com/ee900222/rss">订阅</a>
<!--<a id="MyLinks1_XMLLink" class="aHeaderXML" href="http://www.cnblogs.com/ee900222/rss"><img src="http://www.cnblogs.com/images/xml.gif" alt="订阅" /></a>--></li>
<li><a id="MyLinks1_Admin" class="menu" rel="nofollow" href="http://i.cnblogs.com/">管理</a></li>
</ul>
		<div class="blogStats">
			
			
<!--done-->
随笔- 6&nbsp;
文章- 0&nbsp;
评论- 0&nbsp;

			
		</div><!--end: blogStats -->
	</div><!--end: navigator 博客导航栏 -->
</div><!--end: header 头部 -->

<div id="main">
	<div id="mainContent">
	<div class="forFlow">
		
<div id="post_detail">
<!--done-->
<div id="topics">
	<div class = "post">
		<h1 class = "postTitle">
			<a id="cb_post_title_url" class="postTitle2" href="http://www.cnblogs.com/ee900222/p/redis_2.html">Redis系列之（二）：Redis主从同步，读写分离</a>
		</h1>
		<div class="clear"></div>
		<div class="postBody">
			<div id="cnblogs_post_body"><h1><strong>1. Redis主从同步</strong></h1>
<p>Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步，同步使用的是发布/订阅机制。</p>
<h1><strong>2. 配置主从同步</strong></h1>
<p>Mater Slave的模式，从Slave向Master发起SYNC命令。</p>
<p>可以是1 Master 多Slave，可以分层，Slave下可以再接Slave，可扩展成树状结构。</p>
<h3>2.1 配置Mater，Slave</h3>
<p>配置非常简单，只需在slave的设定文件中指定master的ip和port</p>
<p>Master： test166</p>
<p>修改设定文件，服务绑定到ip上</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># vi /etc/redis.conf
bind 10.86.255.166</pre>
</div>
<p>重启Redis</p>
<p># systemctl restart redis</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># less /etc/redis.conf</pre>
</div>
<p>Slave：&nbsp;test167</p>
<p>修改设定文件，指定Master</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">slaveof &lt;masterip&gt; &lt;masterport&gt;    指定master的ip和port
masterauth &lt;master-password&gt;       master有验证的情况下
slave-read-only yes                设置slave为只读模式</pre>
</div>
<p>也可以用命令行设定：</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">redis 127.0.0.1:9999&gt; slaveof localhost 6379
OK
</pre>
</div>
<h3><strong>2.2 </strong><strong>同期情况确认</strong></h3>
<p>Master：</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">127.0.0.1:6379&gt; INFO replication
# Replication
role:master
connected_slaves:1
slave0:ip=10.86.255.167,port=6379,state=online,offset=309,lag=1
&hellip;&hellip;</pre>
</div>
<p>&nbsp;Slave：</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">127.0.0.1:6379&gt; INFO replication
# Replication
role:slave
master_host:10.86.255.166
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:365
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
</pre>
</div>
<p>同期正常时：</p>
<p>master_link_status:up</p>
<p>master_repl_offset和slave_repl_offset相等，</p>
<p><em>master_last_io_seconds_ago</em><em>在</em><em>10</em><em>秒内。</em></p>
<h3><strong>2.3 Slave</strong><strong>升级为</strong><strong>Master</strong></h3>
<p>Master不可用的情况下，停止Master，将Slave的设定无效化后，Slave升级为Master</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">redis 127.0.0.1:9999&gt; SLAVEOF NO ONE
 OK

redis 127.0.0.1:9999&gt; info
......
role:master
......
</pre>
</div>
<h3><strong>2.4 Health Check</strong></h3>
<p>Slave按照repl-ping-slave-period的间隔（默认10秒），向Master发送ping。</p>
<p>如果主从间的链接中断后，再次连接的时候，2.8以前按照full sync再同期。2.8以后，因为有backlog的设定，backlog存在master的内存里，重新连接之前，如果redis没有重启，并且offset在backlog保存的范围内，可以实现从断开地方同期，不符合这个条件，还是full sync</p>
<p>&nbsp;</p>
<p>用monitor命令，可以看到slave在发送ping</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">127.0.0.1:6379&gt; monitor
OK
1448515184.249169 [0 10.86.255.166:6379] "PING"</pre>
</div>
<h3><strong>2.5 </strong><strong>设置</strong><strong>Master</strong><strong>的写行为</strong></h3>
<p>2.8以后，可以在设定文件中设置，Master只有当有N个Slave处于连接状态时，接受写操作</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">min-slaves-to-write 3
min-slaves-max-lag 10</pre>
</div>
<h1><strong>3. Redis HA</strong><strong>管理工具</strong></h1>
<p>redis-sentinel 能监视同期的状态，发现Master down的时候，会进行failover，将Slave升级为Master，启动后会自动更新sentinel设定文件，发生failover时，会自动修改sentinel和redis的设定文件</p>
<p>&nbsp;</p>
<p>环境：</p>
<p>Master： 10.86.255.167 :6379 &nbsp; &nbsp;sentinel：26379</p>
<p>Slave1： 10.86.255.166 :6379&nbsp;&nbsp; &nbsp;sentinel：26379</p>
<p>Slave2： 10.86.255.167 :7379&nbsp;&nbsp; &nbsp;sentinel：36379</p>
<p>Sentinel的设定文件在/etc/redis-sentinel.conf，对failover的动作等可以进行一些定义，本次主要验证Sentinel的动作，设定文件可以根据具体情况自行调整&nbsp;</p>
<h3>3.1 设定Master，Slave</h3>
<p>参照上文设定Master，Slave，并确认Mater和2个Slave的同期状态正常</p>
<h3>3.2 Master上设定Sentinel</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># vi /etc/redis-sentinel.conf
daemonize yes
sentinel monitor mymaster &lt;master ip&gt; 6379 2
</pre>
</div>
<p>启动sentinel</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># redis-sentinel /etc/redis-sentinel.conf
或
# redis-server /etc/redis-sentinel.conf --sentinel</pre>
</div>
<p>确认</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># redis-cli -p 26379
127.0.0.1:26379&gt; INFO sentinel</pre>
</div>
<p><img src="http://images2015.cnblogs.com/blog/868522/201601/868522-20160111143257928-1248833438.png" alt="" /></p>
<p>确认Master信息</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">127.0.0.1:26379&gt; sentinel masters
</pre>
</div>
<p><img src="http://images2015.cnblogs.com/blog/868522/201601/868522-20160111143318616-1608546253.png" alt="" /></p>
<p>确认Slave信息</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">127.0.0.1:26379&gt; sentinel slaves mymaster
</pre>
</div>
<p><img src="http://images2015.cnblogs.com/blog/868522/201601/868522-20160111143427194-1818461982.png" alt="" /></p>
<h3>3.3 Slave上设定Sentinel</h3>
<p>在slave1上设定sentinel</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># vi /etc/redis-sentinel.conf
daemonize yes
sentinel monitor mymaster &lt;master ip&gt; 6379 2</pre>
</div>
<p>启动slave1</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># redis-sentinel /etc/redis-sentinel.conf</pre>
</div>
<p>在slave2上设定sentinel</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># less /etc/redis-sentinel_36379.conf
daemonize yes
port 36379
sentinel monitor mymaster &lt;master ip&gt; 6379 2</pre>
</div>
<p>启动slave2</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># redis-sentinel /etc/redis-sentinel.conf</pre>
</div>
<h3>3.4 动作确认</h3>
<p>停止Master</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">127.0.0.1:6379&gt; SHUTDOWN</pre>
</div>
<p>确认日志发生fail over</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"># tail /var/log/redis/sentinel.log</pre>
</div>
<p>确认Slave2变成Master，Slave1是Slave</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">test167:7379&gt; info replication
</pre>
</div>
<p><img src="http://images2015.cnblogs.com/blog/868522/201601/868522-20160111144511569-2130337127.png" alt="" /></p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">test166:6379&gt; info replication
</pre>
</div>
<p><img src="http://images2015.cnblogs.com/blog/868522/201601/868522-20160111144547960-335048782.png" alt="" /></p>
<p>启动刚才停掉的Master，确认Master变为Slave</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">10.86.255.166:6379&gt; info replication
</pre>
</div>
<p><img src="http://images2015.cnblogs.com/blog/868522/201601/868522-20160111144721507-435257614.png" alt="" /></p>
<h3>3.5 Sentinel命令</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">127.0.0.1:26379&gt; sentinel masters
127.0.0.1:26379&gt; sentinel slaves mymaster
127.0.0.1:26379&gt; SENTINEL get-master-addr-by-name mymaster
127.0.0.1:26379&gt; SENTINEL reset mymaster
127.0.0.1:26379&gt; SENTINEL failover mymaster
127.0.0.1:26379&gt; SENTINEL flushconfig mymaster</pre>
</div>
<h1>4. 后记</h1>
<p>本文介绍了Redis主从同步，读写分离，及HA，后续会继续研究Redis。</p></div><div id="MySignature"></div>
<div class="clear"></div>
<div id="blog_post_info_block">
<div id="BlogPostCategory"></div>
<div id="EntryTag"></div>
<div id="blog_post_info">
</div>
<div class="clear"></div>
<div id="post_next_prev"></div>
</div>


		</div>
		<div class = "postDesc">posted @ <span id="post-date">2016-01-11 14:51</span> <a href='http://www.cnblogs.com/ee900222/'>ee900222</a> 阅读(<span id="post_view_count">...</span>) 评论(<span id="post_comment_count">...</span>)  <a href ="http://i.cnblogs.com/EditPosts.aspx?postid=5121260" rel="nofollow">编辑</a> <a href="#" onclick="AddToWz(5121260);return false;">收藏</a></div>
	</div>
	<script type="text/javascript">var allowComments=true,isLogined=false,cb_blogId=260854,cb_entryId=5121260,cb_blogApp=currentBlogApp,cb_blogUserGuid='224ee1a5-dbad-e511-9fc1-ac853d9f53cc',cb_entryCreatedDate='2016/1/11 14:51:00';loadViewCount(cb_entryId);</script>
	
</div><!--end: topics 文章、评论容器-->
</div><a name="!comments"></a><div id="blog-comments-placeholder"></div><script type="text/javascript">var commentManager = new blogCommentManager();commentManager.renderComments(0);</script>
<div id='comment_form' class='commentform'>
<a name='commentform'></a>
<div id='divCommentShow'></div>
<div id='comment_nav'><span id='span_refresh_tips'></span><a href='javascript:void(0);' onclick='return RefreshCommentList();' id='lnk_RefreshComments' runat='server' clientidmode='Static'>刷新评论</a><a href='#' onclick='return RefreshPage();'>刷新页面</a><a href='#top'>返回顶部</a></div>
<div id='comment_form_container'></div>
<div class='ad_text_commentbox' id='ad_text_under_commentbox'></div>
<div id='ad_t2'></div>
<div id='opt_under_post'></div>
<div id='ad_c1' class='c_ad_block'></div>
<div id='under_post_news'></div>
<div id='under_post_kb'></div>
<div id='HistoryToday' class='c_ad_block'></div>
<script type='text/javascript'>
$(function () {
    setTimeout(function () { incrementViewCount(cb_entryId); }, 50);
    deliverAdT2();
    deliverAdC1();    
    loadNewsAndKb();
    loadBlogSignature();
    LoadPostInfoBlock(cb_blogId, cb_entryId, cb_blogApp, cb_blogUserGuid);
    GetPrevNextPost(cb_entryId, cb_blogId, cb_entryCreatedDate);
    loadOptUnderPost();
    GetHistoryToday(cb_blogId, cb_blogApp, cb_entryCreatedDate);    
});
</script>
</div>


	</div><!--end: forFlow -->
	</div><!--end: mainContent 主体内容容器-->

	<div id="sideBar">
		<div id="sideBarMain">
			
<!--done-->
<div class="newsItem">
<h3 class="catListTitle">公告</h3>
	<div id="blog-news"></div><script type="text/javascript">loadBlogNews();</script>
</div>

			<div id="blog-calendar" style="display:none"></div><script type="text/javascript">loadBlogDefaultCalendar();</script>
			
			<div id="leftcontentcontainer">
				<div id="blog-sidecolumn"></div><script type="text/javascript">loadBlogSideColumn();</script>
			</div>
			
		</div><!--end: sideBarMain -->
	</div><!--end: sideBar 侧边栏容器 -->
	<div class="clear"></div>
	</div><!--end: main -->
	<div class="clear"></div>
	<div id="footer">
		
<!--done-->
Copyright &copy;2016 ee900222
	</div><!--end: footer -->
</div><!--end: home 自定义的最大容器 -->
</body>
</html>
